home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1998 / MacHack 1998.toast / Programming Contest / Secret Solutions Folder / Problem 02 - Hower of Tanoi / Solution.p < prev   
Encoding:
Text File  |  1998-06-15  |  6.3 KB  |  252 lines  |  [TEXT/CWIE]

  1. (*
  2. Problem 02 - Hower of Tanoi
  3.  
  4. This problem is to solve a variant
  5. of the Tower of Hanoi puzzle.  You remember the Tower of Hanoi, a board
  6. with three pegs, one of which has N disks of size 1, 2, 3, ... N, with the
  7. smallest disk at the top.  In the standard puzzle, the goal is to move all
  8. of the disks from one peg to another peg, by repeatedly moving a disk from
  9. the top of one peg to another peg without ever placing a larger disk on top
  10. of a smaller disk.
  11.  
  12. In our Hower of Tanoi problem, the objective and the constraints are the
  13. same, except that the disks on the first peg are initially in random order.
  14. You can still only move a smaller disk onto a larger disk.
  15.  
  16. Your objective is output the moves required to place all the disks on
  17. peg 3 in order with the smallest disk at the top.  
  18.  
  19. Input specification
  20.  
  21. The
  22. first line of the input file contains an integer M, M<1000, the number of
  23. disks in the problem.  The next M lines contain the numbers 1 .. M, one
  24. number per line, randomly ordered, where the first number is the size of
  25. the top disk on peg 1, the second number is the size of the 2nd
  26. disk from the top, etc.
  27.  
  28. Output specification
  29.  
  30. The output is a sequence of lines, each representing a single move, 
  31. consisting of the source peg number followed by a comma (',') followed
  32. by the destination peg number, followed by a return character.
  33.  
  34. Sample input
  35.  
  36. 2
  37. 2
  38. 1
  39.  
  40. Sample output
  41.  
  42. 1,3
  43. 1,3
  44. *)
  45.  
  46. unit Solution;
  47.  
  48. interface
  49.  
  50. // Do not modify the interface
  51.  
  52.     uses
  53.         Types, Files;
  54.         
  55.     function HowerOfTanoi( const infile, outfile: FSSpec ): OSErr;
  56.  
  57. implementation
  58.  
  59. // Fill in your solution and then submit this folder
  60.  
  61. // Team Name: Example Solution
  62. // 60 mintues
  63.  
  64.     function ProblemFileRead( const infile: FSSpec; var data: Handle ): OSErr; external;
  65.     function ProblemFileWrite( const outfile: FSSpec; data: Handle ): OSErr; external;
  66.     function ProblemReadLineFromHandle( data: Handle; line: Ptr; linelen: longint ): Boolean; external;
  67.     function ProblemGetUInt32( var line: Ptr; var number: UInt32 ): Boolean; external;
  68.  
  69.     type
  70.         DiskArray = array[1..$7FFFFFFF] of UInt32;
  71.         DiskArrayPtr = ^DiskArray;
  72.         Pole = record
  73.             count: UInt32;
  74.             disks: DiskArrayPtr;
  75.         end;
  76.         Board = array[1..3] of Pole;
  77.     
  78.     var
  79.         result: Handle;
  80.         poles: Board;
  81.  
  82. // Ordered - Disks are ordered if the descend along the pole
  83.         
  84.     procedure Assert( must: boolean );
  85.     begin
  86.         if not must then begin
  87.             DebugStr( 'Assert failed!;sc' );
  88.         end;
  89.     end;
  90.     
  91.     function TopDiskSafe( pole: integer ): UInt32;
  92.     begin
  93.         if poles[pole].count = 0 then begin
  94.             TopDiskSafe := $7FFFFFFF;
  95.         end else begin
  96.             TopDiskSafe := poles[pole].disks^[poles[pole].count];
  97.         end;
  98.     end;
  99.     
  100.     function TopDisk( pole: integer ): UInt32;
  101.     begin
  102.         Assert( poles[pole].count <> 0 );
  103.         TopDisk := TopDiskSafe( pole );
  104.     end;
  105.     
  106.     procedure MoveDisk( frompole, topole: integer );
  107.         var
  108.             s: string[10];
  109.             junk: OSErr;
  110.     begin
  111.         Assert( frompole <> topole );
  112.         Assert( TopDisk( frompole ) < TopDiskSafe( topole ) );
  113.         Inc(poles[topole].count);
  114.         poles[topole].disks^[poles[topole].count] := TopDisk( frompole );
  115.         Dec(poles[frompole].count);
  116.         s := 'x,yz';
  117.         s[1] := chr(ord('0')+frompole);
  118.         s[3] := chr(ord('0')+topole);
  119.         s[4] := chr(13);
  120.         junk := PtrAndHand( @s[1], result, length(s) );
  121.     end;
  122.     
  123.     function Otherpole( frompole, topole: integer ): integer;
  124.     begin
  125.         Assert( frompole <> topole );
  126.         Otherpole := 6 - frompole - topole;
  127.     end;
  128.     
  129.     procedure MoveDisks( move: longint; frompole, topole: integer );
  130.     // move 'move' disks from frompole to topole
  131.     // 'move' disks must be in assending order and all must be less than both other poles
  132.     begin
  133.         Assert( frompole <> topole );
  134.         Assert( move >= 0 );
  135.         if move = 0 then begin
  136.         end else if move = 1 then begin
  137.             MoveDisk( frompole, topole );
  138.         end else begin
  139.             MoveDisks( move - 1, frompole, Otherpole( frompole, topole ) );
  140.             MoveDisk( frompole, topole );
  141.             MoveDisks( move - 1, Otherpole( frompole, topole ), topole );
  142.         end;
  143.     end;
  144.     
  145.     function FindPosition( pole: integer; disk: UInt32 ): UInt32;
  146.         var
  147.             i: UInt32;
  148.     begin
  149.         i := 1;
  150.         while i <= poles[pole].count do begin
  151.             if disk > poles[pole].disks^[i] then begin
  152.                 leave;
  153.             end;
  154.             Inc(i);
  155.         end;
  156.         FindPosition := i;
  157.     end;
  158.     
  159.     procedure SortDisks;
  160.     // Sort disks on disk 2 and 3 that are less than TopDisk( 1 ) on to disk 3
  161.         var
  162.             pos: UInt32;
  163.             lessthan: UInt32;
  164.             tomove: UInt32;
  165.     begin
  166.         lessthan := TopDiskSafe( 1 );
  167.         while (poles[2].count <> 0) & (TopDisk( 2 ) < lessthan) do begin
  168.             pos := FindPosition( 3, TopDisk( 2 ) );
  169.             tomove := poles[3].count - pos + 1;
  170.             MoveDisks( tomove, 3, 1 );
  171.             MoveDisk( 2, 3 );
  172.             MoveDisks( tomove, 1, 3 );
  173.         end;
  174.     end;
  175.     
  176.     procedure SolveDisks;
  177.     begin
  178.         // Invariant, pole 2 & 3 are ordered.
  179.         // Objective is to empty pole 1.
  180.         while poles[1].count <> 0 do begin
  181.             if TopDisk( 1 ) < TopDiskSafe( 3 ) then begin
  182.                 MoveDisk( 1, 3 );
  183.             end else if TopDisk( 1 ) < TopDiskSafe( 2 ) then begin
  184.                 MoveDisk( 1, 2 );
  185.             end else begin
  186.                 SortDisks;
  187.                 MoveDisk( 1, 2 );
  188.             end;
  189.         end;
  190.         SortDisks;
  191.     end;
  192.  
  193.     function HowerOfTanoi( const infile, outfile: FSSpec ): OSErr;
  194.         var
  195.             err: OSErr;
  196.             data: Handle;
  197.             linep: Ptr;
  198.             line: packed array[0..256] of char;
  199.             disk_count, disk: UInt32;
  200.             i: longint;
  201.     begin
  202.         err := ProblemFileRead( infile, data );
  203.         if err = noErr then begin
  204.             linep := @line;
  205.             if not ProblemReadLineFromHandle( data, @line, 255 ) | not ProblemGetUInt32( linep, disk_count ) then begin
  206.                 err := -1;
  207.             end;
  208.             if err = noErr then begin
  209.                 for i := 1 to 3 do begin
  210.                     poles[i].count := 0;
  211.                     poles[i].disks := DiskArrayPtr(NewPtr(disk_count * SizeOf(UInt32)));
  212.                     if err = noErr then begin
  213.                         err := MemError;
  214.                     end;
  215.                 end;
  216.                 result := NewHandle( 0 );
  217.                 if err = noErr then begin
  218.                     err := MemError;
  219.                 end;
  220.                 
  221.                 if err = noErr then begin
  222.                     poles[1].count := disk_count;
  223.                     for i := 1 to disk_count do begin
  224.                         linep := @line;
  225.                         if not ProblemReadLineFromHandle( data, @line, 255 ) | not ProblemGetUInt32( linep, disk ) then begin
  226.                             err := -1;
  227.                         end;
  228.                         poles[1].disks^[disk_count-i+1] := disk;
  229.                     end;
  230.                 end;
  231.                 
  232.                 if err = noErr then begin
  233.                     SolveDisks;
  234.                 end;
  235.  
  236.                 for i := 1 to 3 do begin
  237.                     if poles[i].disks <> nil then begin
  238.                         DisposePtr( Ptr( poles[1].disks ) );
  239.                     end;
  240.                 end;
  241.                 if err = noErr then begin
  242.                     err := ProblemFileWrite( outfile, result );
  243.                 end;
  244.                 DisposeHandle( result );
  245.             end;
  246.             DisposeHandle( data );
  247.         end;
  248.         HowerOfTanoi := err;
  249.     end;
  250.  
  251. end.
  252.